#ifndef JSONMAP_H
#define JSONMAP_H

#include "json/json.h"
#include "../JsonMapException.hpp"
#include <forward_list>
#include <memory>
#include <list>

class JsonMapData;

namespace sh
{
/**
 * put list时的方式
 */
enum PutListBehavior
{
    Append, //在原先的list上追加
    Cover   //覆盖原先的list
};

/*
 * json map工具类，基于json cpp封装，该类表示json中的一个value
 * @author: haitao.lin
 */
class JsonMap
{
public:
    explicit JsonMap();

    /*
     * 构造并解析传入的json字符串
     */
    explicit JsonMap(const std::string &content);
    JsonMap(const JsonMap &jsonMap);
    explicit JsonMap(const Json::Value &value);
    ~JsonMap();

    /**
     * 解析json字符串，如果之前有解析过，则覆盖
     */
    bool parser(const std::string &content);

    /*
     * json字符串解析结果
     */
    bool isParserOk() const;

    /**
     * 如果解析错误，则返回错误原因
     */
    std::string getParserErrorMessage() const;

    /**
     * 格式化json
     */
    std::string formatJson() const;

    /**
     * value转对应格式
     */
    std::string toString() const;
    int32_t toInt() const;
    uint32_t toUInt() const;
    int64_t toLong() const;
    uint64_t toULong() const;
    double toDouble() const;
    float toFloat() const;
    bool toBool() const;

    /**
     * value转std::list
     */
    template<class T>
    std::list<T> toList() const
    {
        Json::Value jsonValue = getJsonValue();
        if (!jsonValue.isArray())
        {
            throw sh::JsonMapTypeException("type is not array");
        }
        std::list<T> value;
        uint32_t length = jsonValue.size();
        for (uint32_t index = 0; index < length; index++)
        {
            try
            {
                value.push_back(jsonValue[index].template as<T>());
            }
            catch (Json::Exception &exception)
            {
                throw sh::JsonMapTypeException(
                    std::to_string(index) + "th element type is not " + std::string(typeid(T).name()));
            }
        }
        return value;
    }

    /**
     * 是否包含某个key
     */
    bool containKey(const std::string &key) const;

    /**
     * 根据key获取value
     */
    JsonMap get(const std::string &key) const;

    /**
     * 移除某个key，不存在则无操作
     */
    JsonMap remove(const std::string &key);

    /**
     * 添加key-value，如果已存在，则覆盖
     */
    JsonMap put(const std::string &key, const sh::JsonMap &value);
    JsonMap put(const std::string &key, const std::string &value);
    JsonMap put(const std::string &key, int32_t value);
    JsonMap put(const std::string &key, uint32_t value);
    JsonMap put(const std::string &key, int64_t value);
    JsonMap put(const std::string &key, uint64_t value);
    JsonMap put(const std::string &key, double value);

    /**
     * 添加key-value，value是std::list，putListBehavior表示在原先的list后面追加还是覆盖
     * 如果putListBehavior是追加，而且key已经存在，但是value类型不是list，则认为key不存在，覆盖
     */
    JsonMap put(const std::string &key, const std::list<std::string> &value, PutListBehavior putListBehavior = PutListBehavior::Cover);
    JsonMap put(const std::string &key, const std::list<int32_t> &value, PutListBehavior putListBehavior = PutListBehavior::Cover);
    JsonMap put(const std::string &key, const std::list<uint32_t> &value, PutListBehavior putListBehavior = PutListBehavior::Cover);
    JsonMap put(const std::string &key, const std::list<int64_t> &value, PutListBehavior putListBehavior = PutListBehavior::Cover);
    JsonMap put(const std::string &key, const std::list<uint64_t> &value, PutListBehavior putListBehavior = PutListBehavior::Cover);
    JsonMap put(const std::string &key, const std::list<double> &value, PutListBehavior putListBehavior = PutListBehavior::Cover);

    /**
     * 返回key列表，只包含第一层，如果内部有嵌套json，不递归查找
     */
    std::vector<std::string> keys() const;

    /**
     * 返回key个数，只包含第一层，如果内部有嵌套json，不递归查找
     */
    uint32_t size() const;

    /**
     * 返回json cpp的对象
     */
    Json::Value getJsonValue() const;

private:
    std::unique_ptr<JsonMapData> d;
};

}

#endif //JSONMAP_H
